package ai.tuobot.sdk.util

import ai.tuobot.sdk.inf.PlayCallB
import ai.tuobot.sdk.log.RLog
import ai.tuobot.sdk.model.AudioConfig
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.IOException
import java.util.concurrent.BlockingQueue
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.LinkedBlockingQueue
import kotlin.concurrent.thread
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel


internal class AudioTrackPlayer() {
    private var _playFinish: PlayCallB? = null
    var playFinish: PlayCallB?
        get() = _playFinish
        set(value) {
            _playFinish = value
        }

    private var cfgJsonToAudioConfig: AudioConfig? = null
    private var audioTrack: AudioTrack? = null // 初始化 AudioTrack
    private val audioQueue: BlockingQueue<ByteArray> = LinkedBlockingQueue()

    // 创建一个容量无限的Channel来代替Queue
    private val playCallBQueue = Channel<String>(Channel.UNLIMITED)

    private var playCallbackJob: Job? = null // 用来控制协程的Job

    private val scope = CoroutineScope(Dispatchers.Default)
    
    private var sampleRate = 24000
    val bytesPerSample = 2 // 每个样本的字节数（16-bit）
    companion object {
        private const val TAG = "AudioTrackPlayer"
        val referenceQueue = ConcurrentLinkedQueue<ShortArray>() // 用于存储音频参考信号
    }

    private val audioThread = thread(start = true) {
        while (true) {
            val audioData = audioQueue.take()
            val audioLength = (audioData.size)
            if (audioLength<=0 || audioTrack == null)
                continue
            /*audioTrack?.setNotificationMarkerPosition(audioLength)
            audioTrack?.setPlaybackPositionUpdateListener(object :
                AudioTrack.OnPlaybackPositionUpdateListener {
                override fun onPeriodicNotification(track: AudioTrack?) {
                    RLog.d(TAG, "playAudio onPeriodicNotification")
                }

                override fun onMarkerReached(track: AudioTrack?) {
                    RLog.d(TAG, "playAudio onMarkerReached")
                }
            })*/

            if (playCallbackJob == null){
                RLog.d(TAG, "startPlayCallback")
                startPlayCallback()
            }
            sendToQueue("start,1")
            val playbackTime = calculatePlaybackTime(audioLength, sampleRate, bytesPerSample) * 1000
            sendToQueue("delay,${playbackTime.toLong()}")
            sendToQueue("end,2")


            cfgJsonToAudioConfig?.let {
                if (it.internalAEC){
                    val bitRate = 48000

                    val times = bitRate / sampleRate * 1024

                    //val job =  CoroutineScope(Dispatchers.IO).launch {
                        //RLog.d(TAG, " CoroutineScope(Dispatchers.IO).launch")
                        val chunk = audioData.size / times
                        val remainder = audioData.size % times

                        for (i in 0 until chunk) {
                            //RLog.d(TAG, "put chunk")
                            val start = i * times
                            val end = (i + 1) * times
                            val chunkData = audioData.copyOfRange(start, end)
                            val sArray = byteArrayToShortArray(chunkData)
                            //synchronized(AudioTrackPlayer::class.java) {
                                audioTrack?.write(sArray, 0, sArray.size)
                                referenceQueue.offer(sArray)
                            //}

                        }

                        // 处理剩余数据
                        if (remainder > 0) {
                            //RLog.d(TAG, "put remainder chunk")
                            val start = chunk * times
                            val chunkData = audioData.copyOfRange(start, audioData.size)
                            val sArray = byteArrayToShortArray(chunkData)
                            //synchronized(AudioTrackPlayer::class.java) {
                                audioTrack?.write(sArray, 0, sArray.size)
                                referenceQueue.offer(sArray)
                            //}

                        } else {}
                    //}

                }
                else{
                    try {
                        //synchronized(AudioTrackPlayer::class.java) {
                            audioTrack?.write(audioData, 0, audioData.size)
                        //}
                    } catch (e: IllegalArgumentException) {
                        e.printStackTrace()
                    } catch (e: IOException) {
                        e.printStackTrace()
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }

        }
    }

    // 启动或重启播放回调协程
    fun startPlayCallback() {
        // 启动新的协程
        playCallbackJob = scope.launch {
            try {
                while (isActive) { // 确保协程能够取消
                    val callBStr = playCallBQueue.receive() // 接收Channel中的元素
                    val callBFlagAndV: Pair<String, Int> = Pair(callBStr.split(",")[0], callBStr.split(",")[1].toInt())

                    when (callBFlagAndV.first) {
                        "start" -> _playFinish?.playStart()
                        "end" -> _playFinish?.playFinish()
                        else -> {
                            // 用delay替代Thread.sleep，delay是可取消的
                            delay(callBFlagAndV.second.toLong())
                        }
                    }
                }
            } catch (e: CancellationException) {
                // 当协程被取消时，可以在这里处理清理操作
                clearQueue() // 清空队列
                RLog.d(TAG, "clearQueue")
                playCallbackJob = null
            }
        }
    }

    // 清空队列的方法
    private fun clearQueue() {
        // 清空Channel中的所有剩余元素
        while (!playCallBQueue.isEmpty) {
            playCallBQueue.tryReceive().getOrNull() // 逐个取出并丢弃元素
        }
    }

    fun sendToQueue(callBStr: String) {
        scope.launch {
            playCallBQueue.send(callBStr) // 发送数据到Channel
        }
    }

    fun byteArrayToShortArray(byteArray: ByteArray): ShortArray {
        val shortArray = ShortArray(byteArray.size / 2)
        for (i in shortArray.indices) {
            shortArray[i] = ((byteArray[2 * i].toInt() and 0xFF) or
                    (byteArray[2 * i + 1].toInt() shl 8)).toShort()
        }
        return shortArray
    }

    fun createAudioTrack() {
        val channelConfig = AudioFormat.CHANNEL_OUT_MONO
        val audioFormat = AudioFormat.ENCODING_PCM_16BIT
        val bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat)

        audioTrack = AudioTrack(
            AudioManager.STREAM_MUSIC,
            sampleRate,
            channelConfig,
            audioFormat,
            bufferSize,
            AudioTrack.MODE_STREAM
        )
        audioTrack?.play()
    }

    fun calculatePlaybackTime(dataSizeBytes: Int, sampleRate: Int, bytesPerSample: Int): Double {
        return dataSizeBytes.toDouble() / (sampleRate * bytesPerSample)
    }

    fun releaseAudioTrack() {
        audioTrack?.let {
            it.stop()
            it.release()
        }
        audioTrack = null
    }

    fun playAudio(audioData: ByteArray) {
        rePlay()
        audioQueue.put(audioData)
    }

    fun clearAndPause(){
        audioQueue.clear()
        audioTrack?.pause()
    }

    fun rePlay(){
        try {
            audioTrack?.play()
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    fun setAudioConfig(cfgJsonToAudioConfig: AudioConfig) {
        this.cfgJsonToAudioConfig = cfgJsonToAudioConfig
    }

    fun cancelPlayBackTime(){
        playCallbackJob?.cancel() // 取消当前正在运行的协程
    }

    fun setSampleRate(_sampleRate: Int) {
        sampleRate = _sampleRate
    }

}